// include Marmalade libraries
#include "s3e.h"
#include "IwUtil.h"
#include "Iw2D.h"
#include "IwGxTypes.h"
#include "IwGx.h"
#include "IwSound.h"
#include <time.h>

#include "IGameScreen.h"
#include "GameScreens.h"

#include "StartMenuScreen.h"
#include "MainGameplayScreen.h"
#include "il_assert.h"

#include "ScoreSystem.h"
#include "AudioSystem.h"

AudioSystem* SoundSystem;

IW_MANAGED_IMPLEMENT(ScoreStorage);
IW_CLASS_FACTORY(ScoreStorage);

IW_MANAGED_IMPLEMENT(AudioStorage);
IW_CLASS_FACTORY(AudioStorage);

// main function
int main() {
    // Load information
    IwUtilInit();
    Iw2DInit();
    IwResManagerInit();
    
	// Init IwSound
	IwSoundInit();

	IW_CLASS_REGISTER(ScoreStorage);
	IW_CLASS_REGISTER(AudioStorage);

	#ifdef IW_BUILD_RESOURCES
    IwGetResManager()->AddHandler(new CIwResHandlerWAV);
	#endif

    srand ( time(NULL) );
    
    // make sure the screen is always in landscape mode
    IwGxSetScreenOrient( IW_GX_ORIENT_90 );

    uint16 deltaMs = 0;
    uint64 currTime;
    uint64 lastTime = s3eTimerGetUSTNanoseconds();

    float dt = 1 / 30.0f;
    double accumulator = dt; // at leat one update
    
    // create the score system, is used by all
    ScoreSystem score_system;
    score_system.Load();
    
	GameScreens::Enum active_screen = GameScreens::START_MENU_SCREEN;
    IGameScreen *game_screens[GameScreens::NUM_SCREENS];
    
    game_screens[GameScreens::START_MENU_SCREEN] = new StartMenuScreen( &score_system );
    game_screens[GameScreens::MAIN_GAMEPLAY_SCREEN] = new  MainGameplayScreen( &score_system );

    game_screens[active_screen]->Load();

	IL_ASSERT( s3eTimerGetUSTNanoseconds() != -1, "high resolution timer not supported, enable under Configuration/Timer" );

	SoundSystem = new AudioSystem();
	SoundSystem->Load();

	// Play some MP3 music using s3e Audio (if the codec is supported)
//	if (s3eAudioIsCodecSupported(S3E_AUDIO_CODEC_MP3))
//		s3eAudioPlay("backgroundmusic.mp3", 1);

    while (!s3eDeviceCheckQuitRequest()) {

        currTime = s3eTimerGetUSTNanoseconds();
        float frameTime = (float) ((currTime - lastTime)) * 0.000000001f; 
        lastTime  = currTime;

        if( frameTime > 0.1f ) frameTime = 0.1f;

        accumulator += frameTime;

		// Update Iw Sound Manager
		IwGetSoundManager()->Update();

        while ( accumulator >= dt ) {

            s3eKeyboardUpdate();
            s3ePointerUpdate();

            // do the updating in here
            int next_screen = game_screens[active_screen]->Update( dt );

            if( next_screen > -1 ) {
                game_screens[active_screen]->Unload( );
                game_screens[next_screen]->Load();
                active_screen = (GameScreens::Enum) next_screen;
            }

            accumulator -= dt;
        }

		Iw2DSurfaceClear(0xfff0f0f0);

        // Render active screen
        game_screens[active_screen]->Render();

        // Render information into the screen
        Iw2DSurfaceShow();

        // yield the CPU, allow other processes to use the CPU
        s3eDeviceYield(0);
    }

	// save the current highscores
	score_system.Save();

    game_screens[active_screen]->Unload();
    
    delete game_screens[GameScreens::START_MENU_SCREEN];
    delete game_screens[GameScreens::MAIN_GAMEPLAY_SCREEN];

	SoundSystem->Unload();
	delete SoundSystem;

	// Shutdown IwSound
	IwSoundTerminate();

	IwResManagerTerminate();
    Iw2DTerminate();      // Release the 2D Lib
    IwUtilTerminate();    // Release the Util Library
    
    return 1;
}
